package model;

import java.util.List;

import view.AvailabilityCell;

/**
 * Superclass to all Users. Contains all 
 * behavior that is in common with all Users
 * including hours and skill levels and ways
 * of manipulating that data.
 * 
 * @author Tristan D. Boucher
 * @version Commit #22 9/14/2013
 *
 */
public abstract class AbstractUser implements UserInterface, Comparable<UserInterface>
{
  //Fields
  /**
   * The list of classes this user can tutor if any.
   */
  protected List<Classes> my_classes;

  /**
   * The list of TimeSlots that this user is available to work.
   */
  protected List<TimeSlot[]> my_time_slots;

  /**
   * The first name of this user.
   */
  protected final String my_first_name;

  /**
   * The last name of this user.
   */
  protected final String my_last_name;

  /**
   * The student id number of this user.
   */
  protected final String my_id_number;

  /**
   * The password for this user's login.
   */
  protected final String my_password;

  /**
   * The minimum number of weekly hours a user is willing to work.
   */
  protected int my_min_hours;

  /**
   * The maximum number of weekly hours a user is willing to work.
   */
  protected int my_max_hours;
  
  /**
   * The amount of hours a user is scheduled. Will be unassigned until
   * a schedule is completed. 
   */
  protected int my_weekly_hours;

  /**
   * True if an employee that can only be on the tutor schedule
   * and false if not.
   */
  private boolean my_is_tutor;

  /**
   * True if user is administrator and false if not.
   */
  private boolean my_is_administrator;

  /**
   * True if scheduler and allowed to modify schedule. False if not.
   */
  private boolean my_is_scheduler;

  /**
   * Flag to be set when a user enters their availability.
   * True if availability submitted. False by default.
   */
  private boolean my_availability_entered;

  //Constructors

  /**
   * Constructs a user from the given information upon registration.
   * 
   * @param the_first_name The user's first name.
   * @param the_last_name The user's last name.
   * @param the_id_number The user's student id number.
   * @param the_password The user's password.
   */
  public AbstractUser(final String the_first_name,
                      final String the_last_name,
                      final String the_id_number,
                      final String the_password)
  {
    super();
    my_first_name = the_first_name;
    my_last_name = the_last_name;
    my_id_number = the_id_number;
    my_password = the_password;

    my_availability_entered = false;
  }

  /**
   * Constructs the user from the given information. 
   * 
   * @param the_classes The list of classes that this person is able to tutor.
   *                    May be null if empty such as, at this time, a program
   *                    assistant.
   * @param the_time_slots The array of TimeSlot type lists passes that contains
   *                    the hours one may work.
   * @param the_tutor_choice The choice of whether this user is a tutor or not.
   * @param the_admin_choice The choice of whether this user is an admin or not.
   * @param the_scheduler_choice The choice of whether this user is allowed to 
   *                    modify the schedule or not.
   */
  //  public AbstractUser(final List<Classes> the_classes,
  //                      final List<TimeSlot>[] the_time_slots,
  //                      final boolean the_tutor_choice,
  //                      final boolean the_admin_choice,
  //                      final boolean the_scheduler_choice)
  //  {
  //    my_classes = the_classes;
  //
  //    //TODO: Deep copy.
  //    my_time_slots = the_time_slots;
  //
  //    my_is_tutor = the_tutor_choice;
  //    my_is_administrator = the_admin_choice;
  //    my_is_scheduler = the_scheduler_choice;
  //  }

  //Accessor methods

  /**
   * Returns true if this user is a tutor. False if not.
   * 
   * @return my_is_tutor See above.
   */
  public boolean isTutor()
  {
    return my_is_tutor;
  }

  /**
   * Returns true if this user is an administrator. False if not.
   * 
   * @return my_is_administrator See above.
   */
  public boolean isAdministrator()
  {
    return my_is_administrator;
  }

  /**
   * Promotes this user to an Administrator.
   */
  public void promoteAdmin()
  {
    my_is_administrator = true;
  }

  /**
   * Demotes this user to an Administrator.
   */
  public void demoteAdmin()
  {
    my_is_administrator = false;
  }

  /**
   * All users must have classes they can tutor. If empty,
   * they will simply be left out of the tutor scheduling
   * algorithm.
   * 
   * @return The list of classes that that user can tutor.
   */
  public List<Classes> getClasses()
  {
    return my_classes;
  }

  /**
   * Returns true if the passed password is the same as my_password.
   * 
   * @param the_password The password to be compared.
   * @return Are the passwords the same?.
   */
  public boolean isCorrectPassword(final String the_password)
  {
    boolean to_return = false;

    if (my_password.equals(the_password))
    {
      to_return = true;
    }

    return to_return;
  }

  /**
   * All users have time slots that they can work in laid out
   * in a 2 dimensional array network. Each day has a corresponding
   * number for identification through the enumeration. This 2
   * dimensional array will be an array whose indexed locations 
   * corresponding to each individual day will house a List of
   * TimeSlot objects which define what hours that user is available
   * for work.
   * This will return an array of length 7 where each component of the 
   * array is comprised of Lists containing all those time slots that the
   * current user is able to work.
   * 
   * @return The list of timeslots that this user can work.
   */
  public List<TimeSlot[]> getTimeSlots()
  {
    //TODO: Deep copy.
    return my_time_slots;
  }

  /**
   * Gets the id number of this employee.
   * 
   * @return my_id number.
   */
  public String getID()
  {
    return my_id_number;
  }

  /**
   * Accessor for availability entered flag.
   * 
   * @return Is my availability entered?
   */
  public boolean isAvailabilityEntered()
  {
    return my_availability_entered;
  }

  /**
   * Sets availability to the passed value.
   * 
   * @param the_choice True or false.
   */
  public void setAvailabilityEntered(final boolean the_choice)
  {
    my_availability_entered = the_choice;
  }

  /**
   * Sets the weekly amount of hours that this user has this quarter.
   * Should only be called once the flag has been set and the schedule completed.
   * Otherwise the default will be 0;
   * 
   * @param the_hours The amount of hours that this tutor is scheduled.
   * 
   * @return boolean Did the hours get set?
   */
  public boolean setWeeklyHours(final int the_hours)
  {
    my_weekly_hours = the_hours;
    //TODO: Figure out a way to check and make sure that the schedule has been completed.
    return true;
  }
  
  /**
   * This will add the availability from the gui to the user.
   * Needs hours available, the classes they can tutor, and
   * their min and max hour situation.
   * 
   * @param the_availability_cells The 2d array of availability
   * @param the_classes The array of classes that the users can tutor.
   * @param the_min_max_hours The array of minimum and maximum hours
   * this user can work.
   */
  public void addAvailability(final AvailabilityCell[][] the_availability_cells, 
                              final Classes[] the_classes,
                              final int[] the_min_max_hours)
  {
    setAvailabilityEntered(true);

    for (int i = 0; i < the_availability_cells.length; i++)
    {
      my_time_slots.add(new TimeSlot[the_availability_cells[i].length]);

      for (int j = 0; j < the_availability_cells[i].length; j++)
      {
        my_time_slots.get(i)[j] = the_availability_cells[i][j].getTime();
      }
    }

    for (int i = 0; i < the_classes.length; i++)
    {
      my_classes.add(the_classes[i]);
    }

    my_min_hours = the_min_max_hours[0];
    my_max_hours = the_min_max_hours[1];

  }

  @Override
  public boolean equals(final Object the_o)
  {
    boolean to_return = false;
    User temp = null;

    if (the_o instanceof User)
    {
      temp = (User) the_o;

      if (this.hashCode() == temp.hashCode() &&
          this.my_first_name.equals(temp.my_first_name) &&
          this.my_last_name.equals(temp.my_last_name) &&
          this.my_id_number == temp.my_id_number &&
          this.my_password.equals(temp.my_password))
      {
        to_return = true;
      }
    }
    return to_return;
  }

  @Override
  public int hashCode()
  {
    return Integer.parseInt(my_id_number) * Integer.parseInt(my_id_number);
  }

  @Override
  public int compareTo(final UserInterface the_o)
  {
    return this.hashCode() - the_o.hashCode();
  }

}
